﻿#include "MaterialGraphView.h"

#include "MaterialGraphViewModel.h"
#include "Widgets/ImageWidget.h"
#include "Widgets/RectangleWidget.h"
#include "Widgets/Mouse/MouseWidget.h"
#include "Widgets/CanvasWidget.h"
#include "Framework/Editor.h"

#include "MaterialGraph/Node/MaterialGraphNodeViewModel.h"
#include "MaterialGraph/Node/MaterialGraphNodeView.h"

#include "MaterialGraph/Link/MaterialGraphLinkViewModel.h"
#include "MaterialGraph/Link/MaterialGraphLinkView.h"


void RMaterialGraphView::BindViewModel(TSharedObjectPtr<RMaterialGraphViewModel> InViewModel)
{
    GraphViewModel=InViewModel;

    for(int64_t i=0; i<GraphViewModel->GetNodeNum(); i++)
    {
        auto NodeViewModel=GraphViewModel->GetNode(i);
        CClass* NodeViewClass=REditor::Get()->GetViewClass(NodeViewModel->GetClass());
        auto NodeView=NewObject<RMaterialGraphNodeView>(NodeViewClass,this);
        NodeView->BindViewModel(NodeViewModel);
        NodeViews.Add(NodeView);
    }

    GraphViewModel->OnNodeAdded.Bind([this](int64_t Index){
        auto NodeViewModel=GraphViewModel->GetNode(Index);
        CClass* NodeViewClass=REditor::Get()->GetViewClass(NodeViewModel->GetClass());
        auto NodeView=NewObject<RMaterialGraphNodeView>(NodeViewClass,this);
        NodeView->BindViewModel(NodeViewModel);
        NodeViews.Insert(Index,NodeView);

        if(NodeOverlay)
        {
            auto NodeParentWidget=NewWidget<RWidget>(NodeOverlay);
            NodeParentWidget->Anchor.Fill(NodeOverlay);
            NodeOverlay->MoveSubWidget(NodeOverlay->GetSubWidgetNum()-1,Index);
            NodeView->CreateWidget(NodeParentWidget);
        }
    });

    GraphViewModel->OnNodeRemoved.Bind([this](int64_t Index){
        NodeViews.RemoveAt(Index);

        if(NodeOverlay)
        {
            NodeOverlay->RemoveSubWidgetAt(Index);
        }
    });

    for(int64_t i=0; i<GraphViewModel->GetLinkNum(); i++)
    {
        auto LinkViewModel=GraphViewModel->GetLink(i);
        CClass* LinkViewClass=REditor::Get()->GetViewClass(LinkViewModel->GetClass());
        auto LinkView=NewObject<RMaterialGraphLinkView>(LinkViewClass,this);
        LinkView->BindViewModel(LinkViewModel);
        LinkViews.Add(LinkView);


    }

    GraphViewModel->OnLinkAdded.Bind([this](int64_t Index){
        auto LinkViewModel=GraphViewModel->GetLink(Index);
        CClass* LinkViewClass=REditor::Get()->GetViewClass(LinkViewModel->GetClass());
        auto LinkView=NewObject<RMaterialGraphLinkView>(LinkViewClass,this);
        LinkView->BindViewModel(LinkViewModel);
        LinkViews.Insert(Index,LinkView);

        if(LinkOverlay)
        {
            auto LinkParentWidget=NewWidget<RWidget>(LinkOverlay);
            LinkParentWidget->Anchor.Fill(LinkOverlay);
            LinkOverlay->MoveSubWidget(LinkOverlay->GetSubWidgetNum()-1,Index);
            LinkView->CreateWidget(LinkParentWidget);
        }
    });

    GraphViewModel->OnLinkRemoved.Bind([this](int64_t Index){
        LinkViews.RemoveAt(Index);

        if(LinkOverlay)
        {
            LinkOverlay->RemoveSubWidgetAt(Index);
        }
    });

}

void RMaterialGraphView::CreateWidget(TSharedObjectPtr<RWidget> InParent)
{
    Root=NewWidget<RWidget>(InParent);
    Root->Anchor.Fill(InParent);


    auto GraphMouse=NewWidget<RMouseWidget>(Root);
    RMouseWidgetWeakPtr WeakGraphMouse=GraphMouse;
    GraphMouse->Anchor.Fill(Root);
    GraphMouse->Drag->bIsEnabled=true;
    static SVec2 GraphOffsetOnDragStart;
    GraphMouse->Drag->OnDragStarted.Bind([this,WeakGraphMouse](){
        GraphOffsetOnDragStart=GraphViewModel->GetGraphOffset();
    });
    GraphMouse->Drag->OnDragMoved.Bind([this,WeakGraphMouse](const SVec2& TotalMove){
        GraphViewModel->SetGraphOffset(
            GraphOffsetOnDragStart
            +TotalMove/ GraphViewModel->GraphScale);
    });
    GraphMouse->OnWheeled.BindLambda([this](const SMouseButtonEvent& WheelEvent){
        GraphViewModel->GraphScale+=WheelEvent.GetWheeledDistance() * GraphViewModel->WheelSpeed;
        GraphViewModel->GraphScale=CMathBase::Clamp(GraphViewModel->GraphScale,GraphViewModel->MinScale,GraphViewModel->MaxScale );
        return true;
    });

    LinkOverlay=NewWidget<RWidget>(Root);
    LinkOverlay->Anchor.Fill(Root);
    for(auto& LinkView:LinkViews)
    {
        LinkView->CreateWidget(LinkOverlay);
    }
    
    NodeOverlay=NewWidget<RWidget>(Root);
    NodeOverlay->Anchor.Fill(Root);
    for(auto& NodeView:NodeViews)
    {
        NodeView->CreateWidget(NodeOverlay);
    }
    
    //paint Linking Line
    auto Canvas=NewWidget<RCanvasWidget>(Root);
    RCanvasWidgetWeakPtr WeakCanvas=Canvas;
    Canvas->Anchor.Fill(Root);
    Canvas->OnPaint.BindLambda([this,WeakCanvas](){
        WeakCanvas->Clear();
        if(!GraphViewModel->IsLinking())
        {
            return;
        }

        SVec2 Start= GraphViewModel->GetLinkingStartPos(WeakCanvas);
        SVec2 End= GraphViewModel->GetLinkingEndPos(WeakCanvas);
        
        auto Points= RMaterialGraphLinkViewModel::CalculateLinkingPoints(Start,End);
        
        for(int64_t Index=0; Index<Points.Num()-1; Index++)
        {
            SColor Color;
            if(Index<Points.Num()*0.5f)
            {
                Color=GraphViewModel->GetLinkingStartColor();
            }
            else
            {
                Color=GraphViewModel->GetLinkingEndColor();
            }

            WeakCanvas->AddLine(
                Points[Index],Points[Index+1]
                ,5
                ,Color);
        }
    
    });
}

void RMaterialGraphView::ClearNodeSelection()
{
    GraphViewModel->SelectNode(nullptr);
}

void RMaterialGraphView::DeleteSelectedNode()
{
    GraphViewModel->DeleteSelectedNode();
}

void RMaterialGraphView::AddFloatNodeAtMouse()
{
    GraphViewModel->AddFloatNodeAtMouse(Root);
}

void RMaterialGraphView::AddVectorNodeAtMouse()
{
    GraphViewModel->AddVectorNodeAtMouse(Root);   
}

void RMaterialGraphView::AddOperationNodeAtMouse()
{
    GraphViewModel->AddOperationNodeAtMouse(Root);
}

void RMaterialGraphView::AddVectorOperationNodeAtMouse()
{
    GraphViewModel->AddVectorOperationNodeAtMouse(Root);
}

void RMaterialGraphView::AddSplitVectorNodeAtMouse()
{
    GraphViewModel->AddSplitVectorNodeAtMouse(Root);
}

void RMaterialGraphView::AddCameraNodeAtMouse()
{
    GraphViewModel->AddCameraNodeAtMouse(Root);
}

void RMaterialGraphView::AddDelayBRDFNodeAtMouse()
{
    GraphViewModel->AddDelayBRDFNodeAtMouse(Root);
}

void RMaterialGraphView::AddUnlitNodeAtMouse()
{
    GraphViewModel->AddUnlitNodeAtMouse(Root);
}

void RMaterialGraphView::AddPropertyNodeAtMouse()
{
    GraphViewModel->AddPropertyNodeAtMouse(Root);
}

void RMaterialGraphView::AddTextureNodeAtMouse()
{
    GraphViewModel->AddTextureNodeAtMouse(Root);
}

